<?php

class DAO_MySql extends DAO {

	/**
	 * setSilent
	 *
	 * @param bool $silent
	 * @return void
	 */
	public static function setSilent(bool $silent) {
		$GLOBALS['DB_SILENT'] = $silent;
	}

	/**
	 * add
	 *
	 * @param string $table 数据表名称
	 * @param array $data 字段、值的关联数组
	 * @return string 成功返回新记录的id数
	 * @throws Exception
	 * @throws InvalidArgumentException
	 */
	public static function add($table, $data, $shardKey = array()) {
		$fields = array_keys($data);

		$db = self::newTable($table, $shardKey);
		$db->save($data);

		$lastInsertId = $db->lastInsertId();
		// 字符串主键不支持 lastInsertId
		if ($lastInsertId === '0') {
			// 需要支持返回主键
			return true;
		}
		return $lastInsertId;

	}

	/**
	 * replace
	 *
	 * @param string $table 数据表名称
	 * @param array $data 字段、值的关联数组
	 * @return string 成功返回新记录的id数
	 * @throws Exception
	 * @throws InvalidArgumentException
	 */
	public static function replace($table, $data, $shardKey = array()) {
		$fields = array_keys($data);

		$db = self::newTable($table, $shardKey);
		$db->replace($data);

		$lastInsertId = $db->lastInsertId();
		// 字符串主键不支持 lastInsertId
		if ($lastInsertId === '0') {
			// 需要支持返回主键
			return true;
		}
		return $lastInsertId;

	}

	/**
	 * update 根据主键更新记录
	 *
	 * @param string $table 表名
	 * @param array $data 字段、值的关联数组
	 * @param string $pk 主键
	 * @param mixed $pkValue 主键的值
	 * @return bool 成功返回true
	 * @throws Exception
	 * @throws InvalidArgumentException
	 */
	public static function update($table, $data, $pk, $pkValue, $shardKey = array()) {
		$fields = array_keys($data);
		$conditions = "$pk = ?";
		$params = array($pkValue);

		return self::updateByCondition($table, $data, $conditions, $params, $shardKey);
	}

	/**
	 * updateByCondition
	 * 根据某个字段更新一条或多条记录
	 *
	 * @param string $table
	 * @param array $data
	 * @param string $conditions
	 * @param array $params
	 * @param array $shardKey
	 * @return bool
	 * @throws Exception
	 */
	public static function updateByCondition($table, $data, $conditions, $params, $shardKey = array()) {
		$fields = array_keys($data);
		$db = self::newTable($table, $shardKey);
		return $db->save($data, $conditions, $params);
	}

	/**
	 * remove
	 * 根据主键删除单条记录
	 *
	 * @param string $table 表名
	 * @param string $pk 主键
	 * @param mixed $pkValue 值
	 * @param array $shardKey
	 * @return int
	 * @throws Exception
	 */
	public static function remove($table, $pk, $pkValue, $shardKey = array()) {
		$conditions = "$pk = ?";
		$params = array($pkValue);
		$db = self::newTable($table, $shardKey);
		return $db->remove($conditions, $params);
	}

	/**
	 * removeByCondition
	 * 根据条件删除记录
	 *
	 * @param string $table 表名
	 * @param string $conditions 条件
	 * @param array $params 值
	 * @param array $shardKey
	 * @return int
	 * @throws Exception
	 */
	public static function removeByCondition($table, $conditions, $params, $shardKey = array()) {
		$db = self::newTable($table, $shardKey);
		return $db->remove($conditions, $params);
	}

	/**
	 * execBySql
	 * @param string $table
	 * @param string $sql SQL语句
	 * @param array $params
	 * @param array $shardKey
	 * @return bool
	 * @throws Exception
	 */
	public static function execBySql($table, $sql, $params = array(), $shardKey = array()) {
		if (!$sql || !is_array($params)) {
			throw new InvalidArgumentException('Param $sql Cannt By Empty');
		}

		$db = self::newTable($table, $shardKey);
		return $db->exec($sql, $params);
	}

	/**
	 * get
	 * 根据主键获取一条记录
	 *
	 * @param string $table
	 * @param string $key
	 * @param mixed $value
	 * @param array $columns
	 * @param array $shardKey
	 * @return mixed
	 * @throws Exception
	 */
	public static function get($table, $key, $value, $columns = array('*'), $shardKey = array()) {
		$conditions = "$key = ?";
		$params = array($value);

		return self::find($table, $conditions, $params, $columns, $shardKey);
	}

	/**
	 * findByIds
	 * 根据id获取多条记录
	 *
	 * @param string $table
	 * @param mixed $key
	 * @param mixed $ids
	 * @param array $pageOptions
	 * @param string[] $columns
	 * @param array|string $order
	 * @param array $shardKey
	 * @return array
	 * @throws Exception
	 */
	public static function findByIds($table, $key, $ids, $pageOptions = array(), $columns = array('*'), $order = array(), $shardKey = array()) {
		$return = array();
		if (!empty($ids)) {
			$return = self::findAll($table, $key . ' IN (' . self::buildInSQLClause($ids, $params) . ')', $params, $pageOptions, $columns, $order, $shardKey);
		}
		return $return;
	}

	/**
	 * findAll
	 * 取得多条记录
	 *
	 * @param string $table
	 * @param string|null $conditions
	 * @param array $params
	 * @param array $pageOptions
	 * @param array $columns
	 * @param array|string $order
	 *   fieldName1 => [ASC|DESC]
	 *   fieldName2 => [ASC|DESC]
	 * @param array $shardKey
	 * @return array
	 * @throws Exception
	 */
	public static function findAll($table, $conditions = null, $params = array(), $pageOptions = array(),
	                               $columns = array('*'), $order = array(), $shardKey = array()) {
		if ($params && !is_array($params)) {
			throw new InvalidArgumentException('$params must be an array');
		}

		if ($columns && !is_array($columns)) {
			throw new InvalidArgumentException('$columns must be an array');
		}

		if ($pageOptions && !is_array($pageOptions)) {
			throw new InvalidArgumentException('$pageOptions must be an array');
		}

		if ($order && !is_array($order)) {
			throw new InvalidArgumentException('$order must be an array');
		}

		if ($shardKey && !is_array($shardKey)) {
			throw new InvalidArgumentException('$shardKey must be an array');
		}

		if (!isset($pageOptions['perPage'])) {
			$start = $limit = 0;
		} else {
			$start = $pageOptions['start'];
			$limit = $pageOptions['perPage'];
		}
		$db = self::newTable($table, $shardKey);
		$data = $db->findAll($conditions, $params, $columns, $start, $limit, $order);

		return $data;
	}

	/**
	 * findRange
	 * 按照范围获取mysql 数据
	 *
	 * @param string $table
	 * @param int $start
	 * @param int $limit
	 * @param string[] $columns
	 * @param array $order
	 * @param string|null $conditions
	 * @param array $params
	 * @param array $shardKey
	 * @return array
	 * @throws Exception
	 */
	public function findRange($table, $start = 0, $limit = 0, $columns = array('*'), $order = array(), $conditions = null, $params = array(), $shardKey = array()) {
		$db = self::newTable($table, $shardKey);
		$data = $db->findAll($conditions, $params, $columns, $start, $limit, $order);

		return $data;
	}


	/**
	 * find
	 * 获取一条记录
	 *
	 * @param string $table
	 * @param string $conditions
	 * @param array $params
	 * @param string[] $columns
	 * @param array $shardKey
	 * @return mixed
	 * @throws Exception
	 */
	public static function find($table, $conditions = null, $params = array(), $columns = array('*'), $shardKey = array()) {
		$db = self::newTable($table, $shardKey);
		$data = $db->find($conditions, $params, $columns);

		return $data;
	}

	/**
	 * findBySql
	 *
	 * @param string $table
	 * @param string $sql
	 * @param array $params
	 * @param array $shardKey
	 * @return array
	 * @throws Exception
	 */
	public static function findBySql($table, $sql, $params = array(), $shardKey = array()) {
		$db = self::newTable($table, $shardKey);
		$data = $db->findBySql($sql, $params);

		return $data;
	}

	/**
	 * count
	 * 计算总数
	 *
	 * @param string $table
	 * @param string|null $conditions
	 * @param array $params
	 * @param array $shardKey
	 * @return int
	 * @throws Exception
	 */
	public static function count($table, $conditions = null, $params = array(), $shardKey = array()) {
		if ($params && !is_array($params)) {
			throw new InvalidArgumentException('$params must is an array');
		}

		$db = self::newTable($table, $shardKey);
		$num = $db->count($conditions, $params);

		return $num;
	}

	/**
	 * buildInSQLClause
	 * 根据数据($data)返回, SQL IN 子句
	 *
	 * @param mixed $data
	 * @param mixed $sqlParams
	 * @return string
	 * @throws InvalidArgumentException
	 */
	public static function buildInSQLClause($data, &$sqlParams) {
		if (!is_array($data)) {
			throw new InvalidArgumentException('参数必须是查询数组');
		}

		$params = array();
		foreach ($data as $v) {
			$params[] = '?';
			$sqlParams[] = $v;
		}

		return join(',', $params);
	}

	/**
	 * incr
	 * 给一个字段增加一个单位值
	 *
	 * @param string $table 表名
	 * @param string $field 字段名
	 * @param string|null $conditions 条件
	 * @param array $params 参数
	 * @param integer $unit
	 * @param array $shardKey
	 * @return bool
	 * @throws Exception
	 */
	public static function incr($table, $field, $conditions = null, $params = array(), $unit = 1, $shardKey = array()) {
		if ($params && !is_array($params)) {
			throw new InvalidArgumentException('$params must is an array');
		}

		$db = self::newTable($table, $shardKey);
		return $db->incr($field, $conditions, $params, $unit);
	}

	/**
	 * decr
	 * 给一个字段减少一个单位值
	 *
	 * @param string $table 表名
	 * @param string $field 字段名
	 * @param string|null $conditions 条件
	 * @param array $params 参数
	 * @param integer $unit
	 * @param array $shardKey
	 * @return boolean
	 * @throws Exception
	 */
	public static function decr($table, $field, $conditions = null, $params = array(), $unit = 1, $shardKey = array()) {
		if ($params && !is_array($params)) {
			throw new InvalidArgumentException('$params must is an array');
		}

		$db = self::newTable($table, $shardKey);
		return $db->decr($field, $conditions, $params, $unit);
	}

	/**
	 * 创建 DB 实例
	 * @param $table
	 * @param $shardKey
	 * @return DB_Table
	 * @throws Exception
	 */
	public static function newTable($table, $shardKey) {
		return new DB_Table($table, $shardKey);
	}

}
